import tkinter as tk
from tkinter import messagebox, filedialog
import threading
import queue
import sys
import os
import time
from datetime import datetime
import customtkinter as ctk
import test
from path_config_tool import PathConfigTool
import pyautogui
import keyboard
import pickle
from pynput.mouse import Controller, Listener as MouseListener
from pynput.keyboard import Listener as KeyboardListener, Key
from PIL import Image, ImageTk

# 设置customtkinter主题
ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue")

# 配置PyAutoGUI安全设置（与test.py保持一致，使用默认速度）
pyautogui.FAILSAFE = False
# 使用默认的PAUSE值（0.1秒），与test.py保持一致


class ImagePasteDialog:
    """图片粘贴对话框"""
    
    def __init__(self, parent):
        self.parent = parent
        self.result = None
        self.image_data = None
        
        # 创建对话框窗口
        self.dialog = ctk.CTkToplevel(parent)
        self.dialog.title("粘贴图片")
        self.dialog.geometry("400x280")
        self.dialog.resizable(False, False)
        
        # 设置对话框为模态
        self.dialog.transient(parent)
        self.dialog.grab_set()
        
        # 居中显示
        self.dialog.update_idletasks()
        x = (self.dialog.winfo_screenwidth() // 2) - (400 // 2)
        y = (self.dialog.winfo_screenheight() // 2) - (280 // 2)
        self.dialog.geometry(f"400x280+{x}+{y}")
        
        self.setup_ui()
        
        # 绑定键盘事件
        self.dialog.bind('<Control-v>', self.paste_image)
        self.dialog.focus_set()
    
    def setup_ui(self):
        """设置UI界面"""
        # 主框架
        main_frame = ctk.CTkFrame(self.dialog)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 标题
        title_label = ctk.CTkLabel(
            main_frame,
            text="请粘贴图片",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        title_label.pack(pady=(0, 20))
        
        # 说明文字
        instruction_label = ctk.CTkLabel(
            main_frame,
            text="请先保存截图为文件，然后点击下方按钮选择图片文件\n或使用 Ctrl+V 尝试粘贴（可能不支持所有截图格式）",
            font=ctk.CTkFont(size=11),
            text_color="gray"
        )
        instruction_label.pack(pady=(0, 20))
        
        # 状态显示区域
        self.status_frame = ctk.CTkFrame(main_frame)
        self.status_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 状态标签
        self.status_label = ctk.CTkLabel(
            self.status_frame,
            text="请粘贴或选择图片",
            font=ctk.CTkFont(size=14),
            text_color="gray",
            height=60
        )
        self.status_label.pack(pady=15)
        
        # 按钮框架
        button_frame = ctk.CTkFrame(main_frame)
        button_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 选择文件按钮
        select_button = ctk.CTkButton(
            button_frame,
            text="选择图片文件",
            command=self.select_image_file,
            fg_color="#17a2b8",
            hover_color="#138496"
        )
        select_button.pack(side=tk.LEFT, padx=(0, 10))
        
        # 确定按钮
        self.ok_button = ctk.CTkButton(
            button_frame,
            text="确定",
            command=self.ok_clicked,
            fg_color="#28a745",
            hover_color="#218838",
            state="disabled"
        )
        self.ok_button.pack(side=tk.RIGHT, padx=(10, 0))
        
        # 取消按钮
        cancel_button = ctk.CTkButton(
            button_frame,
            text="取消",
            command=self.cancel_clicked,
            fg_color="#dc3545",
            hover_color="#c82333"
        )
        cancel_button.pack(side=tk.RIGHT)
    
    def paste_image(self, event=None):
        """处理图片粘贴"""
        try:
            # 首先尝试使用PIL从剪贴板获取图片
            from PIL import ImageGrab
            image = ImageGrab.grabclipboard()
            if image:
                self.set_image_data(image)
                return
            
            # 如果PIL方法失败，尝试获取剪贴板文本内容
            try:
                clipboard_data = self.dialog.clipboard_get()
                # 如果是文件路径，直接加载
                if os.path.exists(clipboard_data):
                    self.load_image_from_file(clipboard_data)
                    return
            except tk.TclError:
                pass
            
            # 尝试其他方法获取剪贴板图片
            try:
                import win32clipboard
                win32clipboard.OpenClipboard()
                if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB):
                    # 获取DIB格式的图片数据
                    data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB)
                    if data:
                        # 这里需要将DIB数据转换为PIL图片
                        # 暂时提示用户使用其他方法
                        messagebox.showinfo("提示", "检测到剪贴板中有图片数据，但格式不支持直接粘贴。\n请使用'选择图片文件'按钮选择图片文件。")
                        return
                win32clipboard.CloseClipboard()
            except ImportError:
                pass
            except Exception as e:
                print(f"使用win32clipboard获取图片失败: {e}")
            
            messagebox.showwarning("警告", "剪贴板中没有有效的图片数据\n请使用'选择图片文件'按钮选择图片文件")
            
        except Exception as e:
            messagebox.showerror("错误", f"粘贴图片失败: {str(e)}")
    
    def select_image_file(self):
        """选择图片文件"""
        filetypes = [
            ("图片文件", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff"),
            ("JPEG文件", "*.jpg *.jpeg"),
            ("PNG文件", "*.png"),
            ("所有文件", "*.*")
        ]
        
        filename = filedialog.askopenfilename(
            title="选择图片文件",
            filetypes=filetypes
        )
        
        if filename:
            self.load_image_from_file(filename)
    
    def load_image_from_file(self, filepath):
        """从文件加载图片"""
        try:
            image = Image.open(filepath)
            self.set_image_data(image)
        except Exception as e:
            messagebox.showerror("错误", f"加载图片失败: {str(e)}")
    
    def set_image_data(self, image):
        """设置图片数据（不显示）"""
        try:
            # 保存原始图片数据
            self.image_data = image.copy()
            
            # 更新状态标签
            img_width, img_height = image.size
            self.status_label.configure(
                text=f"图片已加载: {img_width}x{img_height}",
                text_color="#28a745"
            )
            
            # 启用确定按钮
            self.ok_button.configure(state="normal")
            
            print(f"图片已加载: {img_width}x{img_height}")
            
        except Exception as e:
            messagebox.showerror("错误", f"处理图片失败: {str(e)}")
    
    def ok_clicked(self):
        """确定按钮点击"""
        if self.image_data is None:
            messagebox.showwarning("警告", "请先选择或粘贴图片")
            return
        
        try:
            # 保存图片为JPG格式
            output_path = "static/images/message.jpg"
            
            # 确保目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 转换为RGB模式（JPG不支持透明度）
            if self.image_data.mode in ('RGBA', 'LA', 'P'):
                # 创建白色背景
                background = Image.new('RGB', self.image_data.size, (255, 255, 255))
                if self.image_data.mode == 'P':
                    self.image_data = self.image_data.convert('RGBA')
                background.paste(self.image_data, mask=self.image_data.split()[-1] if self.image_data.mode == 'RGBA' else None)
                self.image_data = background
            elif self.image_data.mode != 'RGB':
                self.image_data = self.image_data.convert('RGB')
            
            # 保存为JPG
            self.image_data.save(output_path, 'JPEG', quality=95)
            
            print(f"图片已保存为: {output_path}")
            messagebox.showinfo("成功", f"图片已保存并替换了 {output_path}")
            
            self.result = True
            self.dialog.destroy()
            
        except Exception as e:
            messagebox.showerror("错误", f"保存图片失败: {str(e)}")
    
    def cancel_clicked(self):
        """取消按钮点击"""
        self.result = False
        self.dialog.destroy()
    
    def show(self):
        """显示对话框并等待结果"""
        self.dialog.wait_window()
        return self.result


class MouseRecorder:
    """鼠标录制器 - 基于test2.py实现"""
    
    def __init__(self, stop_callback=None):
        self.mouse = Controller()
        self.recording = []
        self.recording_active = False
        self.playing = False
        self.start_time = 0
        self.keyboard_listener = None
        self.mouse_listener = None
        self.stop_callback = stop_callback  # GUI停止录制的回调函数
        
    def on_move(self, x, y):
        """记录鼠标移动事件"""
        if self.recording_active:
            elapsed_time = time.time() - self.start_time
            event = ('move', x, y, elapsed_time)
            self.recording.append(event)
            # 录制阶段避免频繁打印，减少卡顿
    
    def on_click(self, x, y, button, pressed):
        """记录鼠标点击事件"""
        if self.recording_active:
            elapsed_time = time.time() - self.start_time
            event = ('click', x, y, button, pressed, elapsed_time)
            self.recording.append(event)
            # 点击时不打印明细，减少IO开销
    
    def on_key_press(self, key):
        """检测键盘按键，F9键停止录制"""
        if key == Key.f9:
            # 通过回调通知GUI停止录制，而不是直接停止
            if self.stop_callback:
                self.stop_callback()
            return False
        
    def stop_recording(self):
        """停止录制"""
        self.recording_active = False
        if self.keyboard_listener:
            self.keyboard_listener.stop()
        if self.mouse_listener:
            self.mouse_listener.stop()
        print(f"录制完成，共记录了 {len(self.recording)} 个事件")
    
    def start_recording(self):
        """开始录制鼠标操作"""
        print("开始录制鼠标操作...")
        print("操作完成后，按F9键停止录制")
        self.recording = []
        self.recording_active = True
        
        self.start_time = time.time()
        
        # 创建键盘和鼠标监听器
        self.keyboard_listener = KeyboardListener(on_press=self.on_key_press)
        self.mouse_listener = MouseListener(on_move=self.on_move, on_click=self.on_click)
        
        # 启动监听器
        self.keyboard_listener.start()
        self.mouse_listener.start()
    
    def replay_recording(self, times=1, interval=1.0):
        """回放录制的鼠标操作"""
        if not self.recording:
            print("没有可回放的录制内容，请先录制")
            return
        
        if self.playing:
            print("回放已在进行中")
            return
            
        self.playing = True
        print(f"开始回放鼠标操作，重复 {times} 次，间隔 {interval} 秒... 共 {len(self.recording)} 个事件")
        
        for repeat in range(times):
            if not self.playing:
                break
                
            if repeat > 0:
                print(f"开始第 {repeat + 1} 次回放")
                time.sleep(interval)  # 使用自定义间隔
            
            # 使用高精度计时器，减少漂移
            start_time = time.perf_counter()
            
            for event in self.recording:
                if not self.playing:
                    break
                    
                # 等待到事件应该发生的时间
                while time.perf_counter() - start_time < event[-1]:
                    time.sleep(0.001)
                
                # 执行事件
                try:
                    if event[0] == 'move':
                        _, x, y, _ = event
                        self.mouse.position = (x, y)
                    elif event[0] == 'click':
                        _, x, y, button, pressed, _ = event
                        self.mouse.position = (x, y)
                        if pressed:
                            self.mouse.press(button)
                        else:
                            self.mouse.release(button)
                    # 不再额外sleep，保持顺滑
                    
                except Exception as e:
                    print(f"  执行事件出错: {e}")
                    print(f"  事件数据: {event}")
            
            if self.playing:
                print(f"第 {repeat + 1} 次回放完成")
        
        self.playing = False
        print("回放完成")
    
    def stop_playback(self):
        """停止回放"""
        self.playing = False
        print("回放已停止")
    
    def save_recording(self, filename):
        """保存录制内容到文件"""
        if not self.recording:
            print("没有可保存的录制内容，请先录制")
            return
        
        try:
            with open(filename, 'wb') as f:
                pickle.dump(self.recording, f)
            print(f"录制内容已保存到 {filename}")
        except Exception as e:
            print(f"保存失败: {e}")
    
    def load_recording(self, filename):
        """从文件加载录制内容"""
        try:
            with open(filename, 'rb') as f:
                self.recording = pickle.load(f)
            print(f"已从 {filename} 加载录制内容，共 {len(self.recording)} 个事件")
        except Exception as e:
            print(f"加载失败: {e}")


class RedirectText:
    def __init__(self, text_widget, max_lines=1000):
        self.text_widget = text_widget
        self.max_lines = max_lines
        self.line_count = 0
        self.queue = queue.Queue()
        self.running = True
        self.thread = threading.Thread(target=self.update_text_widget)
        self.thread.daemon = True
        self.thread.start()

    def write(self, string):
        self.queue.put(string)

    def flush(self):
        pass

    def update_text_widget(self):
        buffer = []  # 批量更新缓冲区
        last_update = time.time()

        while self.running:
            try:
                while True:
                    string = self.queue.get_nowait()
                    buffer.append(string)

                    # 批量处理：每积累一定数量的文本或时间间隔后更新
                    if len(buffer) >= 10 or (time.time() - last_update) > 0.2:
                        if buffer:
                            # 批量插入文本
                            full_text = ''.join(buffer)

                            # 检查是否需要清理旧内容
                            new_lines = full_text.count('\n')
                            self.line_count += new_lines

                            if self.line_count > self.max_lines:
                                # 删除旧内容
                                try:
                                    lines = self.text_widget.get("1.0", tk.END).split('\n')
                                    excess_lines = self.line_count - self.max_lines
                                    delete_up_to = 0
                                    for i, line in enumerate(lines):
                                        delete_up_to += 1
                                        if i >= excess_lines:
                                            break

                                    if delete_up_to > 0:
                                        self.text_widget.delete("1.0", f"{delete_up_to}.0")
                                        self.line_count = self.max_lines
                                except Exception:
                                    pass

                            self.text_widget.insert(tk.END, full_text)
                            self.text_widget.see(tk.END)
                            buffer.clear()
                            last_update = time.time()

                            # 只在批量更新后刷新一次
                            try:
                                self.text_widget.update_idletasks()
                            except Exception:
                                pass
            except queue.Empty:
                pass

            # 降低更新频率到100毫秒，减少CPU占用
            time.sleep(0.1)

    def stop(self):
        self.running = False

class WeChatAutomationGUI:
    def __init__(self):
        self.root = ctk.CTk()
        self.root.title("企微社群专用")
        self.root.geometry("800x700")
        self.root.resizable(True, True)
        # 设置最小窗口大小
        self.root.minsize(700, 600)

        # 设置图标
        try:
            self.root.iconbitmap("static/images/logo.ico")
        except Exception:
            pass

        self.setup_ui()
        self.redirect_stdout()

        # 控制变量
        self.is_running = False
        self.automation_thread = None
        self.current_mode = None  # 'auto'、'compensation' 或 'manual'

        # 默认选择自动转发模式
        self.root.after(200, self.select_auto_mode)

        # 初始化鼠标录制器，传入停止录制的回调函数
        self.mouse_recorder = MouseRecorder(stop_callback=self._on_recording_stopped)

        # 启动窗口更新定时器
        self.start_window_updates()

        # 延迟注册快捷键，确保GUI完全初始化
        self.root.after(100, self.register_hotkeys)
    
    def register_hotkeys(self):
        """注册快捷键"""
        try:
            # 使用tkinter的bind方式注册快捷键（更可靠）
            self.root.bind('<KeyPress-F9>', lambda e: self.handle_f9_hotkey())
            self.root.bind('<KeyPress-F10>', lambda e: self.handle_f10_hotkey())
            
            # 同时注册全局快捷键作为备用
            self.f9_hotkey = keyboard.on_press_key("F9", lambda _: self.handle_f9_hotkey())
            self.f10_hotkey = keyboard.on_press_key("F10", lambda _: self.handle_f10_hotkey())
            
            print("快捷键注册成功：F9(录制), F10(回放)")
        except Exception as e:
            print(f"快捷键注册失败: {e}")
    
    def handle_f9_hotkey(self):
        """处理F9快捷键 - 开始/停止录制"""
        if self.current_mode != 'manual':
            print("F9快捷键被触发，但当前不是手动录制模式")
            return
            
        print("F9快捷键被触发")
        # 如果正在录制，停止录制
        if self.mouse_recorder.recording_active:
            print("检测到F9按键，停止录制")
            self.root.after(0, self.stop_recording)
        # 如果未录制且未回放，开始录制
        elif not self.mouse_recorder.playing:
            print("检测到F9按键，开始录制")
            self.root.after(0, self.start_recording)
        else:
            print("回放中，无法开始录制")
    
    def handle_f10_hotkey(self):
        """处理F10快捷键 - 开始/停止回放"""
        if self.current_mode != 'manual':
            print("F10快捷键被触发，但当前不是手动录制模式")
            return
            
        print("F10快捷键被触发")
        # 录制期间禁用F10回放
        if self.mouse_recorder.recording_active:
            print("录制期间禁用回放功能")
            return
        # 如果正在回放，停止回放
        if self.mouse_recorder.playing:
            print("检测到F10按键，停止回放")
            self.root.after(0, self.stop_playback)
        # 如果有录制内容且未在录制，开始回放
        elif self.mouse_recorder.recording:
            print("检测到F10按键，开始回放")
            self.root.after(0, self.start_playback)
        else:
            print("没有录制内容，无法回放")
    
    def _on_recording_stopped(self):
        """当录制被F9键停止时的回调函数"""
        print("录制被F9键停止，通知GUI更新")
        # 在主线程中执行停止录制的GUI更新
        self.root.after(0, self.stop_recording)

    def setup_ui(self):
        # 添加固定联系方式文字（支持复制）
        contact_frame = ctk.CTkFrame(self.root, fg_color="black", height=36)
        contact_frame.pack(fill=tk.X, padx=10, pady=(10, 0))
        contact_frame.pack_propagate(False)  # 防止框架自动调整大小

        # 使用tk.Text而不是CTkTextbox，因为CTkTextbox不支持tag系统
        contact_textbox = tk.Text(
            contact_frame,
            height=1,  # 1行高度
            font=("Microsoft YaHei", 10, "bold"),  # 使用系统字体
            fg="white",
            bg="black",  # 与背景色一致
            wrap="word",  # 如果文字太长则自动换行
            relief="flat",  # 无边框
            highlightthickness=0,  # 无高亮边框
            selectbackground="#4a90e2",  # 选中文本的背景色
            selectforeground="white"  # 选中文本的前景色
        )
        contact_textbox.pack(fill=tk.X, padx=5, pady=3)

        # 插入文字并设置为只读
        contact_textbox.insert("1.0", "如果在使用中有任何问题 请联系vx：PatrickStar-VX")

        # 设置文字居中对齐
        contact_textbox.tag_configure("center", justify='center')
        contact_textbox.tag_add("center", "1.0", "end")

        contact_textbox.configure(state="disabled")  # 设置为只读，但仍可复制

        # 主框架
        main_frame = ctk.CTkFrame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=15, pady=(10, 15))

        # 标题
        title_label = ctk.CTkLabel(
            main_frame,
            text="企业微信自动化工具",
            font=ctk.CTkFont(size=18, weight="bold")
        )
        title_label.pack(pady=(10, 15))

        # 模式选择框架
        mode_frame = ctk.CTkFrame(main_frame)
        mode_frame.pack(fill=tk.X, padx=15, pady=(0, 15))

        # 模式选择标题
        mode_title = ctk.CTkLabel(
            mode_frame,
            text="运行模式",
            font=ctk.CTkFont(size=14, weight="bold")
        )
        mode_title.pack(pady=(10, 5))

        # 模式选择按钮框架
        mode_buttons_frame = ctk.CTkFrame(mode_frame)
        mode_buttons_frame.pack(pady=(0, 10))

        # 自动转发模式按钮
        self.auto_mode_button = ctk.CTkButton(
            mode_buttons_frame,
            text="自动转发模式",
            command=self.select_auto_mode,
            fg_color="#28a745",
            hover_color="#218838"
        )
        self.auto_mode_button.pack(side=tk.LEFT, padx=(0, 10))

        # 掉线补偿模式按钮
        self.compensation_mode_button = ctk.CTkButton(
            mode_buttons_frame,
            text="掉线补偿模式",
            command=self.select_compensation_mode,
            fg_color="#17a2b8",
            hover_color="#138496"
        )
        self.compensation_mode_button.pack(side=tk.LEFT, padx=(0, 10))

        # 手动录制模式按钮
        self.manual_mode_button = ctk.CTkButton(
            mode_buttons_frame,
            text="手动录制模式",
            command=self.select_manual_mode,
            fg_color="#6f42c1",
            hover_color="#5a32a3"
        )
        self.manual_mode_button.pack(side=tk.LEFT)

        # 控制按钮框架
        control_frame = ctk.CTkFrame(main_frame)
        control_frame.pack(fill=tk.X, padx=15, pady=(0, 15))

        # 控制按钮标题
        control_title = ctk.CTkLabel(
            control_frame,
            text="控制按钮",
            font=ctk.CTkFont(size=14, weight="bold")
        )
        control_title.pack(pady=(10, 5))

        # 控制按钮
        buttons_frame = ctk.CTkFrame(control_frame)
        buttons_frame.pack(pady=(0, 10))

        # 开始按钮
        self.start_button = ctk.CTkButton(
            buttons_frame,
            text="开始自动化",
            command=self.start_automation,
            fg_color="#28a745",
            hover_color="#218838",
            state="disabled"
        )
        self.start_button.pack(side=tk.LEFT, padx=(0, 10))

        # 停止按钮
        self.stop_button = ctk.CTkButton(
            buttons_frame,
            text="停止",
            command=self.stop_automation,
            fg_color="#dc3545",
            hover_color="#c82333",
            state="disabled"
        )
        self.stop_button.pack(side=tk.LEFT, padx=(0, 10))

        # 暂停按钮
        self.pause_button = ctk.CTkButton(
            buttons_frame,
            text="暂停 (F8)",
            command=self.toggle_pause,
            fg_color="#ffc107",
            hover_color="#e0a800",
            state="disabled"
        )
        self.pause_button.pack(side=tk.LEFT)

        # 状态标签
        self.status_label = ctk.CTkLabel(
            main_frame,
            text="状态: 请选择运行模式",
            font=ctk.CTkFont(size=12)
        )
        self.status_label.pack(pady=(0, 15))

        # 鼠标录制控制框架
        recorder_frame = ctk.CTkFrame(main_frame)
        recorder_frame.pack(fill=tk.X, padx=15, pady=(0, 15))

        # 录制功能标题
        recorder_title = ctk.CTkLabel(
            recorder_frame,
            text="鼠标操作录制",
            font=ctk.CTkFont(size=14, weight="bold")
        )
        recorder_title.pack(pady=(10, 5))

        # 录制控制按钮
        recorder_control_frame = ctk.CTkFrame(recorder_frame)
        recorder_control_frame.pack(fill=tk.X, padx=15, pady=(0, 10))

        self.record_button = ctk.CTkButton(
            recorder_control_frame,
            text="开始录制 (F9)",
            command=self.start_recording,
            font=ctk.CTkFont(size=12),
            height=28,
            fg_color="#6f42c1",
            hover_color="#5a32a3",
            state="disabled"
        )
        self.record_button.pack(side=tk.LEFT, padx=(0, 6), pady=8)

        self.stop_record_button = ctk.CTkButton(
            recorder_control_frame,
            text="停止录制 (F9)",
            command=self.stop_recording,
            font=ctk.CTkFont(size=12),
            height=28,
            fg_color="#dc3545",
            hover_color="#c82333",
            state="disabled"
        )
        self.stop_record_button.pack(side=tk.LEFT, padx=6, pady=8)

        self.play_button = ctk.CTkButton(
            recorder_control_frame,
            text="开始回放 (F10)",
            command=self.start_playback,
            font=ctk.CTkFont(size=12),
            height=28,
            fg_color="#fd7e14",
            hover_color="#e55a00",
            state="disabled"
        )
        self.play_button.pack(side=tk.LEFT, padx=6, pady=8)

        self.stop_play_button = ctk.CTkButton(
            recorder_control_frame,
            text="停止回放 (F10)",
            command=self.stop_playback,
            font=ctk.CTkFont(size=12),
            height=28,
            fg_color="#dc3545",
            hover_color="#c82333",
            state="disabled"
        )
        self.stop_play_button.pack(side=tk.LEFT, padx=6, pady=8)

        # 回放设置框架
        playback_settings_frame = ctk.CTkFrame(recorder_frame)
        playback_settings_frame.pack(fill=tk.X, padx=15, pady=(0, 10))

        # 回放次数设置
        ctk.CTkLabel(
            playback_settings_frame,
            text="回放次数:",
            font=ctk.CTkFont(size=11)
        ).pack(side=tk.LEFT, padx=(10, 5), pady=8)

        self.repeat_entry = ctk.CTkEntry(
            playback_settings_frame,
            width=60,
            placeholder_text="1",
            font=ctk.CTkFont(size=11)
        )
        self.repeat_entry.pack(side=tk.LEFT, padx=5, pady=8)
        self.repeat_entry.insert(0, "1")

        # 回放间隔设置
        ctk.CTkLabel(
            playback_settings_frame,
            text="回放间隔(秒):",
            font=ctk.CTkFont(size=11)
        ).pack(side=tk.LEFT, padx=(15, 5), pady=8)

        self.interval_entry = ctk.CTkEntry(
            playback_settings_frame,
            width=60,
            placeholder_text="1",
            font=ctk.CTkFont(size=11)
        )
        self.interval_entry.pack(side=tk.LEFT, padx=5, pady=8)
        self.interval_entry.insert(0, "1")

        # 保存/加载按钮
        save_button = ctk.CTkButton(
            playback_settings_frame,
            text="保存录制",
            command=self.save_recording,
            font=ctk.CTkFont(size=11),
            height=26,
            fg_color="#17a2b8",
            hover_color="#138496"
        )
        save_button.pack(side=tk.RIGHT, padx=(0, 6), pady=8)

        load_button = ctk.CTkButton(
            playback_settings_frame,
            text="加载录制",
            command=self.load_recording,
            font=ctk.CTkFont(size=11),
            height=26,
            fg_color="#6c757d",
            hover_color="#5a6268"
        )
        load_button.pack(side=tk.RIGHT, padx=6, pady=8)

        # 日志框架
        log_frame = ctk.CTkFrame(main_frame)
        log_frame.pack(fill=tk.BOTH, expand=True, padx=15, pady=(0, 15))

        # 日志标题和按钮框架
        log_header_frame = ctk.CTkFrame(log_frame)
        log_header_frame.pack(fill=tk.X, padx=10, pady=(10, 5))

        # 日志标题
        log_title = ctk.CTkLabel(
            log_header_frame,
            text="运行日志",
            font=ctk.CTkFont(size=14, weight="bold")
        )
        log_title.pack(side=tk.LEFT)

        # 日志操作按钮框架
        log_buttons_frame = ctk.CTkFrame(log_header_frame)
        log_buttons_frame.pack(side=tk.RIGHT)

        # 清空日志按钮
        clear_log_button = ctk.CTkButton(
            log_buttons_frame,
            text="清空日志",
            command=self.clear_log,
            width=80
        )
        clear_log_button.pack(side=tk.LEFT, padx=(0, 5))

        # 保存日志按钮
        save_log_button = ctk.CTkButton(
            log_buttons_frame,
            text="保存日志",
            command=self.save_log,
            width=80
        )
        save_log_button.pack(side=tk.LEFT)

        # 日志文本区域 - 优化性能
        self.log_text = ctk.CTkTextbox(
            log_frame,
            wrap=tk.WORD,
            font=ctk.CTkFont(size=10)
        )
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))

        # 限制文本框的最大行数，避免内存泄漏和性能问题
        self.max_log_lines = 1000
        self.log_line_count = 0

        # 底部按钮框架
        bottom_frame = ctk.CTkFrame(main_frame)
        bottom_frame.pack(fill=tk.X, padx=15, pady=(0, 15))

        # 路径配置按钮
        path_config_button = ctk.CTkButton(
            bottom_frame,
            text="路径配置",
            command=self.open_path_config,
            fg_color="#17a2b8",
            hover_color="#138496"
        )
        path_config_button.pack(side=tk.LEFT)

        # 使用说明按钮
        help_button = ctk.CTkButton(
            bottom_frame,
            text="使用说明",
            command=self.show_help,
            fg_color="#6c757d",
            hover_color="#5a6268"
        )
        help_button.pack(side=tk.RIGHT)
        
        # 设置窗口焦点，确保能接收键盘事件
        self.root.focus_set()
        self.root.grab_set()  # 捕获所有输入事件

    def redirect_stdout(self):
        """重定向标准输出到GUI"""
        self.stdout_redirector = RedirectText(self.log_text, max_lines=self.max_log_lines)
        sys.stdout = self.stdout_redirector

    def start_window_updates(self):
        """启动窗口更新定时器 - 优化版本"""
        def update_window():
            try:
                # 只在必要时更新，避免拖动时的强制刷新
                if not self._is_dragging:  # 如果没有在拖动窗口
                    self.root.update_idletasks()  # 只更新待处理的任务
            except Exception:
                pass
            # 增加更新间隔到200毫秒，减少CPU占用
            self.root.after(200, update_window)

        # 初始化拖动状态
        self._is_dragging = False

        # 监听窗口拖动事件
        def on_drag_start(event):
            self._is_dragging = True

        def on_drag_end(event):
            self._is_dragging = False
            # 拖动结束后强制更新一次
            try:
                self.root.update_idletasks()
            except Exception:
                pass

        # 绑定拖动事件（跨平台兼容）
        try:
            self.root.bind('<ButtonPress-1>', on_drag_start)
            self.root.bind('<ButtonRelease-1>', on_drag_end)
            self.root.bind('<Motion>', lambda e: None)  # 监听鼠标移动
        except Exception:
            pass

        update_window()

    def select_auto_mode(self):
        """选择自动转发模式"""
        self.current_mode = 'auto'
        self.auto_mode_button.configure(fg_color="#28a745", text="自动转发模式 ✓")
        self.compensation_mode_button.configure(fg_color="#17a2b8", text="掉线补偿模式")
        self.manual_mode_button.configure(fg_color="#6f42c1", text="手动录制模式")
        
        # 启用自动转发相关按钮，禁用录制相关按钮
        self.start_button.configure(state="normal")
        self.stop_button.configure(state="disabled")
        self.pause_button.configure(state="disabled")
        
        # 禁用录制相关按钮
        self.record_button.configure(state="disabled")
        self.stop_record_button.configure(state="disabled")
        self.play_button.configure(state="disabled")
        self.stop_play_button.configure(state="disabled")
        
        self.status_label.configure(text="状态: 自动转发模式已选择", text_color="#28a745")
        print("已选择自动转发模式")

    def select_manual_mode(self):
        """选择手动录制模式"""
        self.current_mode = 'manual'
        self.manual_mode_button.configure(fg_color="#6f42c1", text="手动录制模式 ✓")
        self.auto_mode_button.configure(fg_color="#28a745", text="自动转发模式")
        self.compensation_mode_button.configure(fg_color="#17a2b8", text="掉线补偿模式")
        
        # 禁用自动转发相关按钮，启用录制相关按钮
        self.start_button.configure(state="disabled")
        self.stop_button.configure(state="disabled")
        self.pause_button.configure(state="disabled")
        
        # 启用录制相关按钮
        self.record_button.configure(state="normal")
        self.stop_record_button.configure(state="disabled")
        self.play_button.configure(state="normal")
        self.stop_play_button.configure(state="disabled")
        
        self.status_label.configure(text="状态: 手动录制模式已选择", text_color="#6f42c1")
        print("已选择手动录制模式")

    def select_compensation_mode(self):
        """选择掉线补偿模式"""
        self.current_mode = 'compensation'
        self.compensation_mode_button.configure(fg_color="#17a2b8", text="掉线补偿模式 ✓")
        self.auto_mode_button.configure(fg_color="#28a745", text="自动转发模式")
        self.manual_mode_button.configure(fg_color="#6f42c1", text="手动录制模式")
        
        # 启用掉线补偿相关按钮，禁用录制相关按钮
        self.start_button.configure(state="normal")
        self.stop_button.configure(state="disabled")
        self.pause_button.configure(state="disabled")
        
        # 禁用录制相关按钮
        self.record_button.configure(state="disabled")
        self.stop_record_button.configure(state="disabled")
        self.play_button.configure(state="disabled")
        self.stop_play_button.configure(state="disabled")
        
        self.status_label.configure(text="状态: 掉线补偿模式已选择", text_color="#17a2b8")
        print("已选择掉线补偿模式")

    def start_automation(self):
        """开始自动化"""
        if self.is_running or self.current_mode not in ['auto', 'compensation']:
            return

        # 显示图片粘贴对话框
        print("显示图片粘贴对话框...")
        image_dialog = ImagePasteDialog(self.root)
        result = image_dialog.show()
        
        # 如果用户取消了图片选择，不开始自动化
        if not result:
            print("用户取消了图片选择，自动化未开始")
            return
        
        print("图片已保存，开始自动化程序...")

        # 在开始前重置所有状态，确保从干净的状态开始
        print("正在重置程序状态...")
        if hasattr(test, 'reset_state'):
            test.reset_state()
        print("程序状态已重置，准备开始执行...")

        self.is_running = True
        self.start_button.configure(state="disabled")
        self.stop_button.configure(state="normal")
        self.pause_button.configure(state="normal")
        # 根据当前模式显示不同的运行状态
        if self.current_mode == 'compensation':
            self.status_label.configure(text="状态: 掉线补偿运行中", text_color="#17a2b8")
        else:
            self.status_label.configure(text="状态: 运行中", text_color="#28a745")
        
        # 在新线程中运行自动化
        self.automation_thread = threading.Thread(target=self.run_automation)
        self.automation_thread.daemon = True
        self.automation_thread.start()

    def stop_automation(self):
        """停止自动化"""
        if not self.is_running:
            return
        
        print("正在停止自动化程序...")
        self.is_running = False
        
        # 设置停止标志，让自动化程序能够响应停止信号
        if hasattr(test, 'set_stop_flag'):
            test.set_stop_flag()
        
        # 等待更长时间让程序响应停止信号
        print("等待程序响应停止信号...")
        time.sleep(2.0)  # 增加到2秒
        
        # 如果自动化线程仍在运行，强制终止它
        if self.automation_thread and self.automation_thread.is_alive():
            print("强制终止自动化线程...")
            # 注意：在Python中无法强制终止线程，但我们可以设置更长的等待时间
        
        # 使用test.py中的reset_state函数完全重置所有状态
        if hasattr(test, 'reset_state'):
            test.reset_state()

        # 清除图片位置缓存，防止重新运行时缓存冲突
        try:
            import mouse_fun
            mouse_fun.image_position_cache.clear()
            print("已清除图片位置缓存")
        except Exception as e:
            print(f"清除缓存时出错: {e}")
        
        # 恢复按钮状态
        self.start_button.configure(state="normal")
        self.stop_button.configure(state="disabled")
        self.pause_button.configure(state="disabled")
        self.pause_button.configure(text="暂停 (F8)")  # 重置暂停按钮文本
        # 根据当前模式显示不同的停止状态
        if self.current_mode == 'compensation':
            self.status_label.configure(text="状态: 掉线补偿已停止", text_color="#dc3545")
        else:
            self.status_label.configure(text="状态: 自动转发已停止", text_color="#dc3545")
        
        print("自动化已停止，所有状态已重置")

    def toggle_pause(self):
        """切换暂停状态"""
        if hasattr(test, 'toggle_pause'):
            test.toggle_pause()
            # 更新按钮文本
            if hasattr(test, 'is_paused') and test.is_paused:
                self.pause_button.configure(text="继续 (F8)")
                self.status_label.configure(text="状态: 已暂停", text_color="#ffc107")
            else:
                self.pause_button.configure(text="暂停 (F8)")
                self.status_label.configure(text="状态: 运行中", text_color="#28a745")

    def clear_log(self):
        """清空日志"""
        self.log_text.delete("1.0", tk.END)

    def save_log(self):
        """保存日志"""
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"automation_log_{timestamp}.txt"
            
            with open(filename, 'w', encoding='utf-8') as f:
                log_content = self.log_text.get("1.0", tk.END)
                f.write(log_content)
            
            messagebox.showinfo("成功", f"日志已保存到: {filename}")
        except Exception as e:
            messagebox.showerror("错误", f"保存日志失败: {str(e)}")

    def show_help(self):
        """显示使用说明"""
        help_text = """使用说明：
1. 点击'开始自动化'启动程序
2. 按F8键可以暂停/继续程序执行
3. 程序会自动检测企业微信状态并进行扫码登录
4. 日志区域会实时显示程序运行状态
5. 鼠标录制功能：
   - 按F9键开始/停止录制
   - 按F10键开始/停止回放
   - 可设置回放次数
   - 支持保存和加载录制内容"""
        
        messagebox.showinfo("使用说明", help_text)

    def start_recording(self):
        """开始录制"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        if self.mouse_recorder.recording_active:
            print("录制已在进行中")
            return
        
        if self.mouse_recorder.playing:
            print("请先停止回放")
            return
            
        print("开始录制，最小化界面...")
        
        # 立即开始录制
        self.mouse_recorder.start_recording()
        
        # 最小化GUI窗口
        self.root.iconify()
        
        # 更新按钮状态
        self.record_button.configure(state="disabled")
        self.stop_record_button.configure(state="normal")
        self.record_button.configure(text="录制中... (F9停止)", fg_color="#dc3545")
        
        print("录制已开始，按F9键停止录制")
    
    def stop_recording(self):
        """停止录制"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        if not self.mouse_recorder.recording_active:
            print("录制未在进行中")
            return
        
        print("正在停止录制...")
        self.mouse_recorder.stop_recording()
        
        # 恢复GUI窗口
        self.root.deiconify()
        self.root.lift()
        self.root.focus_force()
        
        # 更新按钮状态
        self.record_button.configure(state="normal")
        self.stop_record_button.configure(state="disabled")
        self.record_button.configure(text="开始录制 (F9)", fg_color="#6f42c1")
        
        print("录制已停止，GUI窗口已恢复")
    
    def start_playback(self):
        """开始回放"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        if not self.mouse_recorder.recording:
            messagebox.showwarning("警告", "没有可回放的录制数据")
            return
            
        if self.mouse_recorder.recording_active:
            messagebox.showwarning("警告", "请先停止录制")
            return
            
        if self.mouse_recorder.playing:
            print("回放已在进行中")
            return
        
        # 获取回放次数和间隔
        try:
            times = int(self.repeat_entry.get())
            if times <= 0:
                times = 1
        except ValueError:
            times = 1
            
        try:
            interval = float(self.interval_entry.get())
            if interval < 0:
                interval = 1.0
        except ValueError:
            interval = 1.0
        
        # 最小化GUI窗口
        self.root.iconify()
        
        # 延迟1秒后开始回放
        self.root.after(1000, lambda: self._start_playback_delayed(times, interval))
    
    def _start_playback_delayed(self, times, interval):
        """延迟开始回放"""
        # 在新线程中执行回放，避免阻塞GUI
        playback_thread = threading.Thread(target=self.mouse_recorder.replay_recording, args=(times, interval))
        playback_thread.daemon = True
        playback_thread.start()
        
        # 更新按钮状态
        self.play_button.configure(state="disabled")
        self.stop_play_button.configure(state="normal")
        self.play_button.configure(text="回放中... (F10停止)", fg_color="#dc3545")
        
        print(f"回放已开始，重复 {times} 次，间隔 {interval} 秒，按F10键停止回放")
        
        # 启动回放监控
        self.start_playback_monitor()
    
    def start_playback_monitor(self):
        """启动回放监控"""
        def monitor_playback():
            while self.mouse_recorder.playing:
                time.sleep(0.1)
            
            # 回放完成后，在主线程中恢复GUI
            self.root.after(0, self._restore_gui_after_playback)
        
        monitor_thread = threading.Thread(target=monitor_playback)
        monitor_thread.daemon = True
        monitor_thread.start()
    
    def _restore_gui_after_playback(self):
        """回放完成后恢复GUI"""
        # 恢复GUI窗口
        self.root.deiconify()
        self.root.lift()
        self.root.focus_force()
        
        # 更新按钮状态
        self.play_button.configure(state="normal")
        self.stop_play_button.configure(state="disabled")
        self.play_button.configure(text="开始回放 (F10)", fg_color="#fd7e14")
        
        print("回放完成，GUI窗口已恢复")
    
    def stop_playback(self):
        """停止回放"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        if not self.mouse_recorder.playing:
            print("回放未在进行中")
            return
            
        print("正在停止回放...")
        self.mouse_recorder.stop_playback()
        
        # 恢复GUI窗口
        self.root.deiconify()
        self.root.lift()
        self.root.focus_force()
        
        # 更新按钮状态
        self.play_button.configure(state="normal")
        self.stop_play_button.configure(state="disabled")
        self.play_button.configure(text="开始回放 (F10)", fg_color="#fd7e14")
        
        print("回放已停止，GUI窗口已恢复")
    
    def save_recording(self):
        """保存录制内容"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        if not self.mouse_recorder.recording:
            messagebox.showwarning("警告", "没有可保存的录制内容")
            return
        
        filename = filedialog.asksaveasfilename(
            defaultextension=".pkl",
            filetypes=[("Pickle files", "*.pkl"), ("All files", "*.*")],
            title="保存录制内容"
        )
        
        if filename:
            self.mouse_recorder.save_recording(filename)
    
    def load_recording(self):
        """加载录制内容"""
        if self.current_mode != 'manual':
            print("请先选择手动录制模式")
            return
            
        filename = filedialog.askopenfilename(
            filetypes=[("Pickle files", "*.pkl"), ("All files", "*.*")],
            title="加载录制内容"
        )
        
        if filename:
            self.mouse_recorder.load_recording(filename)

    def open_path_config(self):
        """打开路径配置工具"""
        try:
            config_tool = PathConfigTool()
            config_tool.run()
            print("路径配置已更新")
        except Exception as e:
            messagebox.showerror("错误", f"打开路径配置工具失败: {str(e)}")

    def run_automation(self):
        """运行自动化程序"""
        try:
            print(f"[{datetime.now().strftime('%H:%M:%S')}] 开始执行自动化程序...")
            
            # 在开始执行前检查停止标志
            if hasattr(test, 'check_should_stop') and test.check_should_stop():
                print("检测到停止标志，程序不执行")
                return
            
            # 在自动化执行过程中定期更新窗口（减少频率以避免干扰时间控制）
            def update_ui():
                if self.is_running:
                    # 更新状态
                    self.root.update()
                    self.root.update_idletasks()
                    # 每1000毫秒更新一次，减少对时间控制的干扰
                    self.root.after(1000, update_ui)
            
            # 启动UI更新
            self.root.after(0, update_ui)
            
            # 执行自动化程序
            test.init()
            time.sleep(2)
            
            # 再次检查停止标志
            if hasattr(test, 'check_should_stop') and test.check_should_stop():
                print("初始化后检测到停止标志，程序不继续执行")
                return
            
            # 在test.main()执行期间定期检查停止信号
            def check_stop_periodically():
                if not self.is_running:
                    # 如果GUI停止标志被设置，设置test.py的停止标志
                    if hasattr(test, 'set_stop_flag'):
                        test.set_stop_flag()
                    return False
                # 每100毫秒检查一次停止信号，提高响应速度
                self.root.after(100, check_stop_periodically)
                return True
            
            # 启动停止信号检查
            check_stop_periodically()
            
            # 执行自动化程序，但定期检查停止信号
            print("开始执行主程序...")
            
            # 将test.main()的执行分成多个小步骤，每步都检查停止信号
            def execute_main_with_stop_check():
                try:
                    # 根据模式决定是否跳过截图
                    skip_screenshots = (self.current_mode == 'compensation')
                    if skip_screenshots:
                        print("掉线补偿模式：跳过截图保存")
                    
                    # 调用test.main()，但在此之前确保停止检查机制已启动
                    test.main(skip_screenshots=skip_screenshots)
                    print(f"[{datetime.now().strftime('%H:%M:%S')}] 自动化程序执行完成")
                except Exception as e:
                    print(f"主程序执行出错: {e}")
            
            # 在新线程中执行主程序，这样GUI可以继续响应
            main_thread = threading.Thread(target=execute_main_with_stop_check)
            main_thread.daemon = True
            main_thread.start()
            
            # 等待主程序完成或停止信号
            while main_thread.is_alive() and self.is_running:
                time.sleep(0.1)  # 每100毫秒检查一次
            
            # 如果是因为停止信号而退出，确保主程序线程结束
            if not self.is_running and main_thread.is_alive():
                print("检测到停止信号，等待主程序线程结束...")
                # 给主程序一点时间响应停止信号
                main_thread.join(timeout=2.0)
                if main_thread.is_alive():
                    print("主程序线程仍在运行，强制设置停止标志")
                    if hasattr(test, 'set_stop_flag'):
                        test.set_stop_flag()
        except Exception as e:
            print(f"[{datetime.now().strftime('%H:%M:%S')}] 程序执行出错: {str(e)}")
        finally:
            # 只有在程序正常完成时才自动停止，避免重复调用
            if self.is_running:
                # 在主线程中更新UI
                self.root.after(0, self.stop_automation)

    def run(self):
        """运行GUI应用"""
        self.root.mainloop()

if __name__ == "__main__":
    app = WeChatAutomationGUI()
    app.run()
